﻿using OnDash.Mathematics.Geometry;
using OnDash.Windowing.Common;
using OnDash.Windowing.GraphicsLibraryFramework;
using Monitor = OnDash.Windowing.GraphicsLibraryFramework.Monitor;

namespace OnDash.Windowing.Desktop;

public unsafe struct MonitorInfo
{
    private readonly MonitorHandle _handle;
    private Monitor* HandleAsPtr => _handle.ToUnsafePtr<Monitor>();
    public MonitorHandle Handle => _handle;
    public string Name { get; private set; }
    public Box2 ClientArea { get; private set; }
    public Box2 WorkArea { get; private set; }
    public int HorizontalResolution => (int)ClientArea.Size.X;
    public int VerticalResolution => (int)ClientArea.Size.Y;

    public float HorizontalScale { get; private set; }
    public float VerticalScale { get; private set; }

    public float HorizontalDpi { get; private set; }
    public float VerticalDpi { get; private set; }

    public int PhysicalWidth { get; private set; }
    public int PhysicalHeight { get; private set; }

    public float HorizontalRawDpi { get; private set; }
    public float VerticalRawDpi { get; private set; }

    private VideoMode[] _supportedVideoModes;

    public IReadOnlyList<VideoMode> SupportedVideoModes =>
        _supportedVideoModes;

    public VideoMode CurrentVideoMode { get; private set; }

    public MonitorInfo(MonitorHandle handle)
    {
        GlfwProvider.EnsureInitialized();

        if (handle.Pointer == IntPtr.Zero)
            throw new ArgumentNullException(nameof(handle));

        _handle = handle;

        Name = Glfw.GetMonitorName(HandleAsPtr);

        Glfw.GetMonitorPos(HandleAsPtr, out var x, out var y);
        var videoMode = Glfw.GetVideoMode(HandleAsPtr);
        ClientArea = new Box2(x, y, x + videoMode->Width, y + videoMode->Height);

        Glfw.GetMonitorWorkarea(HandleAsPtr, out var workAreaX, out var workAreaY, out var workAreaWidth,
            out var workAreaHeight);
        WorkArea = new Box2(workAreaX, workAreaY, workAreaWidth, workAreaHeight);

        Glfw.GetMonitorPhysicalSize(HandleAsPtr, out var width, out var height);
        PhysicalWidth = width;
        PhysicalHeight = height;

        Glfw.GetMonitorContentScale(HandleAsPtr, out var horizontalScale, out var verticalScale);
        HorizontalScale = horizontalScale;
        VerticalScale = verticalScale;

        var defaultDpi = Monitors.GetPlatformDefaultDpi();

        HorizontalDpi = defaultDpi * HorizontalScale;
        VerticalDpi = defaultDpi * VerticalScale;

        HorizontalRawDpi = CalculateDpi(HorizontalResolution, PhysicalWidth);
        VerticalRawDpi = CalculateDpi(VerticalResolution, PhysicalHeight);

        _supportedVideoModes = Glfw.GetVideoModes(HandleAsPtr);
        CurrentVideoMode = *Glfw.GetVideoMode(HandleAsPtr);
    }

    private float CalculateDpi(int pixels, float length) =>
        pixels / length * 25.4f;
}